
package com.borqs.music.util;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.HashMap;
@Deprecated
public class BitRateReader {
    public int bitrates = 0;

    public int getBitRate(String file) {
        bitrates = 0;
        RandomAccessFile rfile = null;
        try {
            rfile = new RandomAccessFile(file, "r");
            int id3v2Size = getId3Size(rfile);
            rfile.seek(id3v2Size);
            seekMP3Frame(rfile);
        } catch (Exception e) {
        } finally {
            if (rfile != null) {
                try {
                    rfile.close();
                } catch (IOException e) {
                }
            }
        }

        return bitrates;
    }

    public int getId3Size(RandomAccessFile file) throws Exception {
        final int size;
        byte[] buffer = new byte[4];
        byte[] bufferTag = new byte[3];
        file.seek(0);

        // read the tag if it exists
        file.read(bufferTag, 0, 3);
        final String tag = new String(bufferTag, 0, 3);
        if (tag.equals("ID3") == false) {
            return 0;
        }
        // read the major and minor version bytes & flag bytes
        file.read(buffer, 0, 3);

        // read the size
        file.read(buffer, 0, 4);
        size = (buffer[0] << 21) + (buffer[1] << 14) + (buffer[2] << 7) + buffer[3];
        return size;
    }

    public void seekMP3Frame(final RandomAccessFile seekFile) throws Exception {
        boolean syncFound = false;
        do {
            byte first = seekFile.readByte();
            if (first == (byte) 0xFF) {
                long filePointer = seekFile.getFilePointer();
                byte second = (byte) (seekFile.readByte() & (byte) 0xE0);
                if (second == (byte) 0xE0) {
                    seekFile.seek(filePointer - 1);
                    // seek the next frames, recursively
                    syncFound = seekNextMP3Frame(seekFile, numberMP3SyncFrame);
                }
                seekFile.seek(filePointer);
            }
        } while (!syncFound);

    }

    private boolean seekNextMP3Frame(final RandomAccessFile file, final int iterations)
            throws Exception {

        if (iterations == 0) {
            return true;
        }

        try {
            readFrameHeader(file);
        } catch (Exception ex) {
            return false;
        }

        final int size = getFrameSize();

        if ((size <= 0) || (size > file.length())) {
            return false;
        }

        byte[] buffer = new byte[size - 4];

        file.read(buffer);
        long filePointer = file.getFilePointer();
        byte first = file.readByte();
        if (first == (byte) 0xFF) {
            byte second = (byte) (file.readByte() & (byte) 0xE0);
            if (second == (byte) 0xE0) {
                file.seek(filePointer);

                // recursively find the next frames
                return seekNextMP3Frame(file, iterations - 1);
            }
        }

        return false;
    }

    private int getFrameSize() {
        if (frequency == 0) {
            return 0;
        }
        final int size;
        final int paddingByte = padding ? 1 : 0;

        if (layer == 3) { // Layer I
            size = (int) ((((12 * bitrates) / frequency) + paddingByte) * 4);
        } else {
            size = (int) (((144 * bitrates) / frequency) + paddingByte);
        }
        return size;
    }

    private void readFrameHeader(final RandomAccessFile file) throws Exception {
        final byte[] buffer = new byte[4];
        file.read(buffer);

        // sync
        if ((buffer[0] != (byte) 0xFF) || ((buffer[1] & (byte) 0xE0) != (byte) 0xE0)) {
            throw new Exception("MP3 Frame sync bits not found");
        }
        mpegVersion = (byte) ((buffer[1] & MASK_MP3_VERSION) >> 3);
        layer = (byte) ((buffer[1] & MASK_MP3_LAYER) >> 1);
        final int bitRateValue = (buffer[2] & MASK_MP3_BITRATE) | (buffer[1] & MASK_MP3_ID)
                | (buffer[1] & MASK_MP3_LAYER);
        final Long object = (Long) BITRATE.get(new Long(bitRateValue));
        if (object != null) {
            if (object.longValue() != bitrates) {
                variableBitRate = true;
            }
            bitrates = object.intValue();
        } else {
            throw new Exception("Invalid bit rate");
        }
        final int frequencyValue = (buffer[2] & MASK_MP3_FREQUENCY) >>> 2;
        if (mpegVersion == 3) { // Version 1.0
            switch (frequencyValue) {
                case 0:
                    frequency = 44.1;
                    break;
                case 1:
                    frequency = 48.0;
                    break;
                case 2:
                    frequency = 32.0;
                    break;
            }
        } else if (mpegVersion == 2) { // Version 2.0
            switch (frequencyValue) {
                case 0:
                    frequency = 22.05;
                    break;
                case 1:
                    frequency = 24.00;
                    break;
                case 2:
                    frequency = 16.00;
                    break;
            }
        } else if (mpegVersion == 00) { // Version 2.5
            switch (frequencyValue) {
                case 0:
                    frequency = 11.025;
                    break;
                case 1:
                    frequency = 12.00;
                    break;
                case 2:
                    frequency = 8.00;
                    break;
            }
        } else {
            throw new Exception("Invalid MPEG version");
        }
        padding = (buffer[2] & MASK_MP3_PADDING) != 0;
    }

    public boolean isVariableBitRate() {
        return variableBitRate;
    }

    private boolean variableBitRate = false;
    private int mpegVersion;
    private double frequency;
    private boolean padding;
    private int layer;

    private static final int numberMP3SyncFrame = 1;

    private static final int BIT7 = 0x80;
    private static final int BIT6 = 0x40;
    private static final int BIT5 = 0x20;
    private static final int BIT4 = 0x10;
    private static final int BIT3 = 0x08;
    private static final int BIT2 = 0x04;
    private static final int BIT1 = 0x02;
    private static final int MASK_MP3_BITRATE = BIT7 | BIT6 | BIT5 | BIT4;
    private static final int MASK_MP3_ID = BIT3;
    private static final int MASK_MP3_LAYER = BIT2 | BIT1;
    private static final int MASK_MP3_FREQUENCY = BIT3 + BIT2;
    private static final int MASK_MP3_VERSION = BIT4 | BIT3;
    private static final int MASK_MP3_PADDING = BIT1;

    private static final HashMap<Long, Long> BITRATE = new HashMap<Long, Long>();
    // MPEG-1, Layer I (E)
    static {
        BITRATE.put(new Long(0x1E), new Long(32));
        BITRATE.put(new Long(0x2E), new Long(64));
        BITRATE.put(new Long(0x3E), new Long(96));
        BITRATE.put(new Long(0x4E), new Long(128));
        BITRATE.put(new Long(0x5E), new Long(160));
        BITRATE.put(new Long(0x6E), new Long(192));
        BITRATE.put(new Long(0x7E), new Long(224));
        BITRATE.put(new Long(0x8E), new Long(256));
        BITRATE.put(new Long(0x9E), new Long(288));
        BITRATE.put(new Long(0xAE), new Long(320));
        BITRATE.put(new Long(0xBE), new Long(352));
        BITRATE.put(new Long(0xCE), new Long(384));
        BITRATE.put(new Long(0xDE), new Long(416));
        BITRATE.put(new Long(0xEE), new Long(448));

        // MPEG-1, Layer II (C)
        BITRATE.put(new Long(0x1C), new Long(32));
        BITRATE.put(new Long(0x2C), new Long(48));
        BITRATE.put(new Long(0x3C), new Long(56));
        BITRATE.put(new Long(0x4C), new Long(64));
        BITRATE.put(new Long(0x5C), new Long(80));
        BITRATE.put(new Long(0x6C), new Long(96));
        BITRATE.put(new Long(0x7C), new Long(112));
        BITRATE.put(new Long(0x8C), new Long(128));
        BITRATE.put(new Long(0x9C), new Long(160));
        BITRATE.put(new Long(0xAC), new Long(192));
        BITRATE.put(new Long(0xBC), new Long(224));
        BITRATE.put(new Long(0xCC), new Long(256));
        BITRATE.put(new Long(0xDC), new Long(320));
        BITRATE.put(new Long(0xEC), new Long(384));

        // MPEG-1, Layer III (A)
        BITRATE.put(new Long(0x1A), new Long(32));
        BITRATE.put(new Long(0x2A), new Long(40));
        BITRATE.put(new Long(0x3A), new Long(48));
        BITRATE.put(new Long(0x4A), new Long(56));
        BITRATE.put(new Long(0x5A), new Long(64));
        BITRATE.put(new Long(0x6A), new Long(80));
        BITRATE.put(new Long(0x7A), new Long(96));
        BITRATE.put(new Long(0x8A), new Long(112));
        BITRATE.put(new Long(0x9A), new Long(128));
        BITRATE.put(new Long(0xAA), new Long(160));
        BITRATE.put(new Long(0xBA), new Long(192));
        BITRATE.put(new Long(0xCA), new Long(224));
        BITRATE.put(new Long(0xDA), new Long(256));
        BITRATE.put(new Long(0xEA), new Long(320));

        // MPEG-2, Layer I (6)
        BITRATE.put(new Long(0x16), new Long(32));
        BITRATE.put(new Long(0x26), new Long(48));
        BITRATE.put(new Long(0x36), new Long(56));
        BITRATE.put(new Long(0x46), new Long(64));
        BITRATE.put(new Long(0x56), new Long(80));
        BITRATE.put(new Long(0x66), new Long(96));
        BITRATE.put(new Long(0x76), new Long(112));
        BITRATE.put(new Long(0x86), new Long(128));
        BITRATE.put(new Long(0x96), new Long(144));
        BITRATE.put(new Long(0xA6), new Long(160));
        BITRATE.put(new Long(0xB6), new Long(176));
        BITRATE.put(new Long(0xC6), new Long(192));
        BITRATE.put(new Long(0xD6), new Long(224));
        BITRATE.put(new Long(0xE6), new Long(256));

        // MPEG-2, Layer II (4)
        BITRATE.put(new Long(0x14), new Long(8));
        BITRATE.put(new Long(0x24), new Long(16));
        BITRATE.put(new Long(0x34), new Long(24));
        BITRATE.put(new Long(0x44), new Long(32));
        BITRATE.put(new Long(0x54), new Long(40));
        BITRATE.put(new Long(0x64), new Long(48));
        BITRATE.put(new Long(0x74), new Long(56));
        BITRATE.put(new Long(0x84), new Long(64));
        BITRATE.put(new Long(0x94), new Long(80));
        BITRATE.put(new Long(0xA4), new Long(96));
        BITRATE.put(new Long(0xB4), new Long(112));
        BITRATE.put(new Long(0xC4), new Long(128));
        BITRATE.put(new Long(0xD4), new Long(144));
        BITRATE.put(new Long(0xE4), new Long(160));

        // MPEG-2, Layer III (2)
        BITRATE.put(new Long(0x12), new Long(8));
        BITRATE.put(new Long(0x22), new Long(16));
        BITRATE.put(new Long(0x32), new Long(24));
        BITRATE.put(new Long(0x42), new Long(32));
        BITRATE.put(new Long(0x52), new Long(40));
        BITRATE.put(new Long(0x62), new Long(48));
        BITRATE.put(new Long(0x72), new Long(56));
        BITRATE.put(new Long(0x82), new Long(64));
        BITRATE.put(new Long(0x92), new Long(80));
        BITRATE.put(new Long(0xA2), new Long(96));
        BITRATE.put(new Long(0xB2), new Long(112));
        BITRATE.put(new Long(0xC2), new Long(128));
        BITRATE.put(new Long(0xD2), new Long(144));
        BITRATE.put(new Long(0xE2), new Long(160));
    }
}
